package com.itheima.demo03stream;

import com.itheima.demo01lambda.Person;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class Demo01StreamFunction {
    public static void main(String[] args) {

    }

    @Test
    public void testForEach(){
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");

//        list.stream().forEach((String str) -> {
//            System.out.println(str);
//        });

        // 省略写法
//        list.stream().forEach(str -> System.out.println(str));

        // 方法引用
        list.stream().forEach(System.out::println);
    }

    @Test
    public void testCount(){
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");

        System.out.println(list.stream().count());
    }

    @Test
    public void testFilter(){
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");

        // 找出字符长度为3的人名
//        list.stream().filter((String str) -> {
//            return str.length() == 3;
//        }).forEach(System.out::println); // 调用一个终结方法，否则中间的操作不会执行

        // 省略写法
        // 找出字符长度为3的人名
        list.stream().filter(str -> str.length() == 3
        ).forEach(System.out::println); // 调用一个终结方法，否则中间的操作不会执行
    }

    @Test
    public void testLimit(){
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");

        // limit 方法可以对流进行截取，只取用前n个
        list.stream().limit(3).forEach(System.out::println);
    }

    @Test
    public void testSkip(){
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");

        // 如果希望跳过前几个元素，可以使用 skip 方法获取一个截取之后的新流
        list.stream().skip(2).forEach(System.out::println);
    }

    @Test
    public void testMap(){
        Stream<String> stream = Stream.of("11", "22", "33");

//        Stream<Integer> newStream = stream.map((String s) -> {
//            return Integer.parseInt(s);
//        });
//        newStream.forEach(System.out::println);

//        stream.map(s -> Integer.parseInt(s)).forEach(System.out::println);

        // 简化代码
        // 如果需要将流中的元素映射到另一个流中，可以使用 map 方法
        stream.map(Integer::parseInt).forEach(System.out::println);
    }

    @Test
    public void testSorted(){
        Stream<Integer> stream = Stream.of(23, 44, 11, 56, 45);

        // 以自然排序
        stream.sorted().forEach(System.out::println);

        System.out.println("------------------------------------");
        Stream<Integer> stream2 = Stream.of(23, 44, 11, 56, 45);
//        stream2.sorted((o1, o2) -> {
//            return o2 - o1;
//        }).forEach(System.out::println);

        // 指定排序
        stream2.sorted((o1, o2) -> o2 - o1).forEach(System.out::println);
    }

    @Test
    public void testDistinct(){
        // 去重
        Stream.of(3, 5, 1, 8, 1).distinct().forEach(System.out::println);
    }

    @Test
    public void testDistinct2(){
        // 自定义类型是根据对象的hashCode和equals来去除重复元素的
        Stream.of(new Person("刘德华", 53, 172),
                new Person("张学友", 58, 175),
                new Person("张学友", 58, 175),
                new Person("黎明", 52, 176))
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    public void testMatch(){
        Stream<Integer> stream = Stream.of(3, 5, 7, 8, 1);

        // allMatch: 元素是否全部满足条件
        boolean b = stream.allMatch(num -> num > 5);
        System.out.println("allMatch: " + b);

        // anyMatch: 元素是否任意有一个满足条件
        Stream<Integer> stream1 = Stream.of(3, 5, 7, 8, 1);
        boolean b1 = stream1.anyMatch(num -> num > 3);
        System.out.println("anyMatch: " + b1);

        // noneMatch: 元素是否全部不满足条件
        Stream<Integer> stream2 = Stream.of(3, 5, 7, 8, 1);
        boolean b2 = stream2.noneMatch(num -> num < 0);
        System.out.println("noneMatch: " + b2);
    }

    @Test
    public void testFind(){
        Stream<Integer> stream = Stream.of(3, 5, 7, 8, 1);
        // 保证返回第一个元素
        Optional<Integer> first = stream.findFirst();
        System.out.println(first.get());

        // 返回任意一个元素
        Stream<Integer> stream1 = Stream.of(3, 5, 7, 8, 1);
        Optional<Integer> any = stream1.findAny();
        System.out.println(any.get());
    }

    @Test
    public void testMaxAndMin(){
        Stream<Integer> stream = Stream.of(3, 5, 7, 8, 1);
        // 升序排序
        Optional<Integer> max = stream.max((o1, o2) -> o1 - o2);
        System.out.println("max is " + max.get());

        Stream<Integer> stream1 = Stream.of(3, 5, 7, 8, 1);
        // 升序排序
        Optional<Integer> min = stream1.min((o1, o2) -> o1 - o2);
        System.out.println("min is " + min.get());
    }

    @Test
    public void testReduce(){
        Stream<Integer> stream = Stream.of(3, 5, 7, 8, 1);
        // 第一个参数相当于默认值
        // reduce如何执行：
        // 1、第一次将默认值赋给x，取出第一个元素给y，进行操作
        // 2、第二次将操作后的结果赋给x，取出第二个元素给y，进行操作
        // 3、第三次将操作后的结果赋给x，取出第三个元素给y，进行操作
        // 4、第四次将操作后的结果赋给x，取出第四个元素给y，进行操作
        // 4、第五次将操作后的结果赋给x，取出第五个元素给y，进行操作
        Integer sum = stream.reduce(0, (x, y) -> x + y);

        System.out.println("sum is " + sum);

        // reduce的最大值计算
        Stream<Integer> stream1 = Stream.of(3, 5, 7, 8, 1);
        // 第一个参数相当于默认值
        // reduce如何执行：
        // 1、第一次将默认值赋给x，取出第一个元素给y，进行操作
        // 2、第二次将操作后的结果赋给x，取出第二个元素给y，进行操作
        // 3、第三次将操作后的结果赋给x，取出第三个元素给y，进行操作
        // 4、第四次将操作后的结果赋给x，取出第四个元素给y，进行操作
        // 4、第五次将操作后的结果赋给x，取出第五个元素给y，进行操作
        Integer max = stream1.reduce(0, (x, y) -> {
            return x > y ? x : y;
        });
        System.out.println("max is " + max);
    }

    @Test
    public void testMapAndReduce(){
        Stream<Person> personStream = Stream.of(new Person("刘德华", 55, 173),
                new Person("张学友", 56, 174),
                new Person("黎明", 53, 176),
                new Person("郭富城", 52, 170));
        // 求出所有人年龄的总和
//        Integer totalAge = personStream.map((p) -> p.getAge())
//                .reduce(0, (x, y) -> x + y);
        // 简化写法
        Integer totalAge = personStream.map((p) -> p.getAge())
                .reduce(0, Integer::sum);
        System.out.println("totalAge = " + totalAge);

        Stream<Person> personStream1 = Stream.of(new Person("刘德华", 55, 173),
                new Person("张学友", 56, 174),
                new Person("黎明", 53, 176),
                new Person("郭富城", 52, 170));
        // 求出所有人中身材最高的
//        Integer maxHeight = personStream1.map((p) -> p.getHeight())
//                .reduce(0, (x, y) -> {
//                    return x > y ? x : y;
//                });
        // 简化写法
        Integer maxHeight = personStream1.map((p) -> p.getHeight())
                .reduce(0, Integer::max);
        System.out.println("maxHeight " + maxHeight);

        // 统计“a“出现的次数
        // map执行后 -> 1, 0, 0, 1, 1, 0, 0
        Integer count = Stream.of("a", "b", "c", "a", "a", "b", "d")
                .map(p -> {
                    if ("a" == p) {
                        return 1;
                    } else {
                        return 0;
                    }
                }).reduce(0, Integer::sum);
        System.out.println("count = " + count);
    }

    @Test
    public void testMapToInt(){
        // 找出大于3的值，基本类型比包装类型快（不需要自动拆箱和装箱），且节省内存
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 6, 7);
        integerStream.mapToInt(Integer::intValue)
                .filter(n -> n > 3)
                .forEach(System.out::println);
    }

    @Test
    public void testConcat(){
        Stream<String> stream1 = Stream.of("aa");
        Stream<String> stream2 = Stream.of("bb");

        Stream<String> newStream = Stream.concat(stream1, stream2);
        newStream.forEach(System.out::println);
    }
}
